package com.hoapital.outpbillwork.function;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hoapital.outpbillwork.module.controller.dto.OrderDetail;
import com.hoapital.outpbillwork.module.controller.dto.OrderQuery;
import com.hoapital.outpbillwork.module.controller.dto.OrderQueryAll;
import com.hoapital.outpbillwork.module.controller.vo.OrderInfoRecive;
import com.hoapital.outpbillwork.module.entity.*;
import com.hoapital.outpbillwork.module.service.*;
import com.hospital.api.RemoteDictionaryService;
import com.hospital.common.core.constants.AllFinalValueUtils;
import com.hospital.common.core.result.ErrorTip;
import com.hospital.common.core.result.SuccessTip;
import com.hospital.common.core.result.Tip;
import com.hospital.common.core.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author lvyao
 * @description 数据查询方法
 * @date 2022/3/7
 */
@Slf4j
@Service
public class SelectDataThread {
    @Resource
    private OutpOrderDescTempService outpOrderDescTempService;

    @Resource
    private OutpOrderDescService outpOrderDescService;

    @Resource
    private OutpPrepayRcptTempService outpPrepayRcptTempService;

    @Resource
    private OutpDoctorAssistantService outpDoctorAssistantService;

    @Resource
    private ClinicMasterService clinicMasterService;

    @Resource
    private OutpDoctorPrescMasterService outpDoctorPrescMasterService;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private OrderVsBillnoService orderVsBillnoService;

    @Resource
    private RemoteDictionaryService remoteDictionaryService;

    public Tip getOrderData(String requestVal) throws InterruptedException {
        Tip tip = new SuccessTip();
        OrderQueryAll orderQueryAll = new OrderQueryAll();
        OrderInfoRecive orderInfo = null;
        try {
            orderInfo = JSON.parseObject(requestVal, OrderInfoRecive.class);
        } catch (Exception e) {
            tip = new ErrorTip("1001", "入参格式转换出错:" + e.getMessage());
            return tip;
        }
        if (orderInfo.getQuerySql() == null || orderInfo.getQuerySql().trim().equals("")) {
            orderInfo.setQuerySql(DateUtil.getDay());
        }
        List<OrderQuery> orderQueryList = new ArrayList<>();
        String sql = orderInfo.getQuerySql();
        PatientInfo patInfo;
        List<Integer> clinicMasterOutpIdLsit = new ArrayList<>();
        List<OutpOrderDesc> outpOrderDescListOrder = new ArrayList<>();
        List<OutpOrderDescTemp> outpOrderDescTempListOrder = new ArrayList<>();
        try {
            patInfo = orderInfo.getPatInfo();
            String patientId = patInfo.getPatientId();
            QueryWrapper<ClinicMaster> clinicMasterQueryWrapper = new QueryWrapper<>();
            //通过type准备医嘱数据及门诊挂号查询的条件
            switch (orderInfo.getType()) {
                case AllFinalValueUtils.ALL_BILL_ITEMS:
                    clinicMasterQueryWrapper.apply(AllFinalValueUtils.APPLY_QUE_OUTPVISIT_BY_STARTDATE, patientId, sql);
                    break;
                case AllFinalValueUtils.UNBILL_ITEMS:
                    OutpOrderDescTemp outpOrderDescTemp = outpOrderDescTempService.getOrderTempDate(sql.substring(0, 14), sql.substring(14));
                    if (patientId == null || patientId.trim().equals("")) {
                        patientId = outpOrderDescTemp.getPatientId();
                    }
                    clinicMasterQueryWrapper.apply(AllFinalValueUtils.APPLY_PID_OUTPID, patientId, outpOrderDescTemp.getOutpId());
                    break;
                case AllFinalValueUtils.BILL_ITEMS:
                    OutpOrderDesc outpOrderDesc = outpOrderDescService.getOrderTempDate(sql.substring(0, 14), sql.substring(14));
                    if (patientId == null || patientId.trim().equals("")) {
                        patientId = outpOrderDesc.getPatientId();
                    }
                    clinicMasterQueryWrapper.apply(AllFinalValueUtils.APPLY_PID_OUTPID, patientId, outpOrderDesc.getOutpId());
                    break;
                case AllFinalValueUtils.CANCEL_ORDER_NO:
                    if (!outpPrepayRcptTempService.updateFlag(patInfo.getPatientId(), sql)) {
                        return new ErrorTip("1002", "更新订单有校标记失败！");
                    }
                    return new SuccessTip();
                case AllFinalValueUtils.QUERY_ORDER_NO:
                    List<OutpPrepayRcptTemp> outpPrepayRcptTempList = new ArrayList<>();
                    OutpPrepayRcptTemp outpPrepayRcptTemp = outpPrepayRcptTempService.getOne(new QueryWrapper<OutpPrepayRcptTemp>().
                            eq(AllFinalValueUtils.ORDER_NO_FIELD_NAME, sql));
                    if (patientId == null || patientId.trim().equals("")) {
                        patientId = outpPrepayRcptTemp.getPatientId();
                    }
                    outpPrepayRcptTempList.add(outpPrepayRcptTemp);
                    orderQueryAll.setOutpPrepayRcptTemp(outpPrepayRcptTempList);
                    List<OrderVsBillno> orderVsBillnoList = orderVsBillnoService.list(new QueryWrapper<OrderVsBillno>().
                            eq(AllFinalValueUtils.ORDER_NO_FIELD_NAME, sql));
                    orderVsBillnoList.stream().forEach(orderVsBillno -> {
                        //2、查询此患者的计费医嘱主记录 outp_order_desc
                        CompletableFuture outpOrderDesc5 = CompletableFuture.runAsync(
                                () -> {
                                    outpOrderDescListOrder.addAll(outpOrderDescService.list(new QueryWrapper<OutpOrderDesc>().
                                            apply(AllFinalValueUtils.APPLY_QUE_VISITDATE_VISITNO, orderVsBillno.getBillNo().substring(0, 14),
                                                    orderVsBillno.getBillNo().substring(14))));
                                    clinicMasterOutpIdLsit.addAll(outpOrderDescListOrder.stream().map(OutpOrderDesc::getOutpId).distinct().collect(Collectors.toList()));
                                }, threadPoolExecutor
                        );
                        //3、查询此患者的未计费医嘱主记录  outp_order_desc_temp
                        CompletableFuture outpOrderDescTemp5 = CompletableFuture.runAsync(
                                () -> {
                                    outpOrderDescTempListOrder.addAll(outpOrderDescTempService.list(new QueryWrapper<OutpOrderDescTemp>().
                                            apply(AllFinalValueUtils.APPLY_QUE_VISITDATE_VISITNO,
                                                    orderVsBillno.getBillNo().substring(0, 14), orderVsBillno.getBillNo().substring(14))));
                                    clinicMasterOutpIdLsit.addAll(outpOrderDescTempListOrder.stream().map(OutpOrderDescTemp::getOutpId).distinct().collect(Collectors.toList()));
                                }, threadPoolExecutor
                        );
                        CompletableFuture.allOf(outpOrderDesc5, outpOrderDescTemp5).join();
                    });
                    //去重
                    List<Integer> collect = clinicMasterOutpIdLsit.stream().distinct().collect(Collectors.toList());
                    clinicMasterQueryWrapper.eq(AllFinalValueUtils.PATIENT_ID_FIELD_NAME, patientId).in(AllFinalValueUtils.OUTP_VISIT_TIME, collect);
                    break;
                case AllFinalValueUtils.TIME_ORDER_NO:
                    outpPrepayRcptTempList = outpPrepayRcptTempService.list(new QueryWrapper<OutpPrepayRcptTemp>().
                            apply(AllFinalValueUtils.BILL_ORDER_LIST,
                                    patInfo.getPatientId(), sql.split(",")[0], sql.split(",")[1]));
                    orderQueryAll.setOutpPrepayRcptTemp(outpPrepayRcptTempList);
                    tip.setData(orderQueryAll);
                    return tip;
                default:
                    return new ErrorTip("1003", "入参中传入type未定义");
            }
            // 1、查询给出时间前该患者的就诊记录
            CompletableFuture<List<ClinicMaster>> clinicMasterCompletable = CompletableFuture.supplyAsync(
                    () -> {
                        List<ClinicMaster> clinicMasterList1 = clinicMasterService.list(clinicMasterQueryWrapper);
                        return clinicMasterList1;
                    }, threadPoolExecutor
            );
            String type = orderInfo.getType();
            String finalPatientId = patientId;
            CompletableFuture<List<ClinicMaster>> listCompletableFuture = clinicMasterCompletable.whenComplete(
                    (result, e) -> {
                        if (result != null) {
                            result.stream().forEach(clinicMaster -> {
                                OrderQuery orderQuery = new OrderQuery();
                                String outpId = String.valueOf(clinicMaster.getOutpId());
                                orderQuery.setVisitId(String.valueOf(outpId));
                                //单次就诊的医嘱及明细
                                List<OrderDetail> orderDetailList = new ArrayList<>();
                                //初始化查询的医嘱及明细
                                List<OutpOrderDesc> outpOrderDescList = new ArrayList<>();
                                List<OutpOrderDescTemp> outpOrderDescTempList = new ArrayList<>();
                                List<OutpDoctorAssistant> outpDoctorAssistantList = new ArrayList<>();
                                List<OutpDoctorPrescItems> outpDoctorPrescItemsList = new ArrayList<>();
                                //2、查询此患者的计费医嘱主记录 outp_order_desc
                                CompletableFuture outpOrderDesc = CompletableFuture.runAsync(
                                        () -> {
                                            if (type.equals(AllFinalValueUtils.QUERY_ORDER_NO)) {
                                                outpOrderDescList.addAll(outpOrderDescListOrder);
                                            } else if (type.equals(AllFinalValueUtils.BILL_ITEMS)) {
                                                outpOrderDescList.addAll(outpOrderDescService.list(new QueryWrapper<OutpOrderDesc>().
                                                        apply(AllFinalValueUtils.APPLY_QUE_VISITDATE_VISITNO, sql.substring(0, 14), sql.substring(14))));
                                            } else if (type.equals(AllFinalValueUtils.UNBILL_ITEMS)) {
                                            } else {
                                                outpOrderDescList.addAll(outpOrderDescService.list(new QueryWrapper<OutpOrderDesc>().
                                                        apply(AllFinalValueUtils.APPLY_PID_OUTPID_ORDER, finalPatientId, outpId)));
                                            }
                                        }, threadPoolExecutor
                                );
                                //3、查询此患者的未计费医嘱主记录  outp_order_desc_temp
                                CompletableFuture outpOrderDescTemp = CompletableFuture.runAsync(
                                        () -> {
                                            if (type.equals(AllFinalValueUtils.QUERY_ORDER_NO)) {
                                                outpOrderDescTempList.addAll(outpOrderDescTempListOrder);
                                            } else if (type.equals(AllFinalValueUtils.UNBILL_ITEMS)) {
                                                outpOrderDescTempList.addAll(outpOrderDescTempService.list(new QueryWrapper<OutpOrderDescTemp>().
                                                        apply(AllFinalValueUtils.APPLY_QUE_VISITDATE_VISITNO, sql.substring(0, 14), sql.substring(14))));
                                            } else if (type.equals(AllFinalValueUtils.BILL_ITEMS)) {
                                            } else {
                                                outpOrderDescTempList.addAll(outpOrderDescTempService.list(new QueryWrapper<OutpOrderDescTemp>().
                                                        apply(AllFinalValueUtils.APPLY_PID_OUTPID_ORDER, finalPatientId, outpId)));
                                            }
                                        }, threadPoolExecutor
                                );
                                //4、查询此患者的所有计费及未计费医嘱项目明细 OUTP_DOCTOR_ASSISTANT  无处方明细
                                CompletableFuture outpDoctorAssistant = CompletableFuture.runAsync(
                                        () -> {
                                            List<OutpDoctorAssistant> outpDoctorAssistants = outpDoctorAssistantService.list(new QueryWrapper<OutpDoctorAssistant>().
                                                    apply(AllFinalValueUtils.APPLY_PID_OUTPID, finalPatientId, outpId));
                                            outpDoctorAssistants.stream().forEach(outpDoctorAssistant1 -> {
                                                outpDoctorAssistant1.setItemClassName(remoteDictionaryService.getclinicItemClassDictList().stream().filter(p -> p.getClassCode().equals(outpDoctorAssistant1.getItemClass())).collect(Collectors.toList()).get(0).getClassName());
                                                outpDoctorAssistant1.setPerformedByName(remoteDictionaryService.getdeptDictList().stream().filter(p -> p.getDeptCode().equals(outpDoctorAssistant1.getPerformedBy())).collect(Collectors.toList()).get(0).getDeptName());
                                                outpDoctorAssistant1.setDeptName(remoteDictionaryService.getdeptDictList().stream().filter(p -> p.getDeptCode().equals(outpDoctorAssistant1.getDept())).collect(Collectors.toList()).get(0).getDeptName());
                                            });
                                            outpDoctorAssistantList.addAll(outpDoctorAssistants);


                                        }, threadPoolExecutor
                                );
                                //5、查询此患者的所有计费及未计费处方的明细 从outp_doctor_presc_master 得到 outp_doctor_presc_items
                                CompletableFuture outpDoctorPrescItems = CompletableFuture.runAsync(
                                        () -> {
                                            outpDoctorPrescItemsList.addAll(outpDoctorPrescMasterService.getAllItems(finalPatientId, outpId));
                                        }, threadPoolExecutor
                                );
                                //待数据准备完成及所有都查询完成
                                CompletableFuture.allOf(outpDoctorAssistant, outpOrderDesc, outpOrderDescTemp, outpDoctorPrescItems).join();
                                //根据医嘱封装医嘱及明细
                                CompletableFuture outpOrderDescOrder = CompletableFuture.runAsync(
                                        () -> {
                                            outpOrderDescList.stream().forEach(outpOrderDesc1 -> {
                                                OrderDetail orderDetail = getOrderDetail(outpOrderDesc1, outpDoctorAssistantList, outpDoctorPrescItemsList,
                                                        outpOrderDesc1.getVisitDate(), outpOrderDesc1.getVisitNo());
                                                if (orderDetail != null) {
                                                    orderDetailList.add(orderDetail);
                                                }
                                            });
                                        }, threadPoolExecutor
                                );
                                CompletableFuture outpOrderDescTempOrder = CompletableFuture.runAsync(
                                        () -> {
                                            outpOrderDescTempList.stream().forEach(outpOrderDescTemp1 -> {
                                                OrderDetail orderDetail = getOrderDetail(outpOrderDescTemp1, outpDoctorAssistantList, outpDoctorPrescItemsList,
                                                        outpOrderDescTemp1.getVisitDate(), outpOrderDescTemp1.getVisitNo());
                                                if (orderDetail != null) {
                                                    orderDetailList.add(orderDetail);
                                                }
                                            });
                                        }, threadPoolExecutor
                                );
                                CompletableFuture.allOf(outpOrderDescOrder, outpOrderDescTempOrder).join();
                                //将医嘱list放入对象
                                orderQuery.setOrderDetailList(orderDetailList);
                                orderQueryList.add(orderQuery);
                            });

                        }
                    });
            //若添加多个  CompletableFuture 到  allof 则需要  CompletableFuture[]
            //此句终结才能获取数据
            listCompletableFuture.get();
            if ((orderQueryList == null || orderQueryList.size() <= 0) && !orderInfo.getType().equals(AllFinalValueUtils.QUERY_ORDER_NO)) {
                tip = new ErrorTip("1004", "从入参中获取条件无查询结果！");
                return tip;
            }
        } catch (Exception e) {
            tip = new ErrorTip("1005", "从入参中获取条件查询结果失败！" + e.getMessage());
            return tip;
        }
        orderQueryAll.setOrderQueryList(orderQueryList);
        tip.setData(orderQueryAll);
        if (orderInfo.getType().equals(AllFinalValueUtils.ALL_BILL_ITEMS)) {
            Thread.sleep(5000);
        }
        return tip;
    }

    //获取明细项目
    public OrderDetail getOrderDetail(Object outpOrderDescTemp1, List<OutpDoctorAssistant> outpDoctorAssistantList, List<OutpDoctorPrescItems> outpDoctorPrescItemsList,
                                      Timestamp visitDate, Integer visitNo) {
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOutpOrderDescTemp(outpOrderDescTemp1);
        List<Object> itemList = new ArrayList<>();
        itemList.addAll(outpDoctorAssistantList.stream().filter(outpDoctorAssistant1 ->
                outpDoctorAssistant1.getVisitDate().getTime() == visitDate.getTime() &&
                        outpDoctorAssistant1.getVisitNo().equals(visitNo)).collect(Collectors.toList()));
        itemList.addAll(outpDoctorPrescItemsList.stream().filter(outpDoctorPrescItems1 ->
                outpDoctorPrescItems1.getVisitDate().getTime() == visitDate.getTime() &&
                        outpDoctorPrescItems1.getVisitNo().equals(visitNo)).collect(Collectors.toList()));
        orderDetail.setOutpDoctorAssistantList(itemList);
        return orderDetail;
    }
}
